package com.aygxy.carproject.service.impl;


import com.alibaba.fastjson.JSON;
import com.aygxy.carproject.ex.ServiceCode;
import com.aygxy.carproject.ex.ServiceException;
import com.aygxy.carproject.mapper.UserMapper;
import com.aygxy.carproject.pojo.user.dto.UserAddDTO;
import com.aygxy.carproject.pojo.user.dto.UserLoginInfoDTO;
import com.aygxy.carproject.pojo.user.dto.UserUpdateDTO;
import com.aygxy.carproject.pojo.user.entity.User;
import com.aygxy.carproject.pojo.user.vo.UserListItemVO;
import com.aygxy.carproject.pojo.user.vo.UserStandardVO;
import com.aygxy.carproject.security.UserDetail;
import com.aygxy.carproject.service.UserService;
import org.springframework.beans.factory.annotation.Value;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
@Slf4j
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Value("${csmall.jwt.secret-key}")
    private String secretKey;


    @Override
    public List<UserListItemVO> list() {
        return userMapper.list();
    }

    @Override
    public String login(UserLoginInfoDTO userLoginInfoDTO) {
        log.debug("开始处理【登录认证】的业务，参数：{}", userLoginInfoDTO);

        // 调用AuthenticationManager的authenticate()方法执行认证
        // 在authenticate()方法的执行过程中
        // Spring Security会自动调用UserDetailsService对象的loadUserByUsername()获取用户详情
        // 并根据loadUserByUsername()返回的用户详情自动验证是否启用、判断密码是否正确等
        Authentication authentication
                = new UsernamePasswordAuthenticationToken(
                userLoginInfoDTO.getUsername(),
                userLoginInfoDTO.getPassword());
        Authentication authenticateResult
                = authenticationManager.authenticate(authentication);
        log.debug("Spring Security已经完成认证，且认证通过，返回的结果：{}", authenticateResult);
        log.debug("返回认证信息中的当事人（Principal）类型：{}", authenticateResult.getPrincipal().getClass().getName());
        log.debug("返回认证信息中的当事人（Principal）数据：{}", authenticateResult.getPrincipal());

        // 从认证返回结果中取出当事人信息
        UserDetail principal =(UserDetail)authenticateResult.getPrincipal();
        Long id = principal.getId();
        log.debug("认证信息中的用户id：{}", id);
        String username = principal.getUsername();
        log.debug("认证信息中的用户名：{}", username);
        Collection<GrantedAuthority> authorities = principal.getAuthorities();
        log.debug("认证信息中的权限：{}", authorities);
        String authorityListString = JSON.toJSONString(authorities);
        log.debug("认证信息中的权限转换为JSON字符串：{}", authorityListString);
        // 生成JWT，并返回
        // 准备Claims值
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", id);
        claims.put("username", username);
        claims.put("authorities", authorityListString);

        // JWT的过期时间
        Date expiration = new Date(System.currentTimeMillis() + 15 * 24 * 60 * 60 * 1000);
        log.debug("即将生成JWT数据，过期时间：{}", expiration);

        // JWT的组成：Header（头：算法和Token类型）、Payload（载荷）、Signature（签名）
        String jwt = Jwts.builder()
                // Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                // Payload
                .setClaims(claims)
                .setExpiration(expiration)
                // Signature
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();
        log.debug("已经生成JWT数据：{}", jwt);
        return jwt;
    }

    @Override
    public void insert(UserAddDTO userAddDTO) {
        log.debug("开始处理【添加用户】的业务，参数：{}", userAddDTO);
        // 从参数中取出用户名
        String username = userAddDTO.getUsername();
        log.debug("检查用户名【{}】是否被占用……", username);
        // 调用Mapper对象的countByUsername()根据用户名统计用户账号的数量
        int countByUsername = userMapper.countByUsername(username);
        // 判断统计结果是否大于0
        if (countByUsername > 0) {
            // 是：抛出ServiceException（ERR_CONFLICT）
            String message = "添加用户失败，用户名【" + username + "】已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 从参数中取出手机号码
        String phone = userAddDTO.getPhone();
        log.debug("检查手机号码【{}】是否被占用……", phone);
        // 调用Mapper对象的countByPhone()根据手机号码统计用户账号的数量
        int countByPhone = userMapper.countByPhone(phone);
        // 判断统计结果是否大于0
        if (countByPhone > 0) {
            // 是：抛出ServiceException（ERR_CONFLICT）
            String message = "添加用户失败，手机号码【" + phone + "】已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 从参数中取出电子邮箱
        String email = userAddDTO.getEmail();
        log.debug("检查电子邮箱【{}】是否被占用……", email);
        // 调用Mapper对象的countByEmail()根据电子邮箱统计用户账号的数量
        int countByEmail = userMapper.countByEmail(email);
        // 判断统计结果是否大于0
        if (countByEmail > 0) {
            // 是：抛出ServiceException（ERR_CONFLICT）
            String message = "添加用户失败，电子邮箱【" + email + "】已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 创建User对象，将作为插入时的参数
        User user = new User();
        // 将参数的各属性复制到Admin对象中：BeanUtils.copyProperties()
        BeanUtils.copyProperties(userAddDTO, user);
        // 补全Admin对象的属性：status，值为0，表示启用对象
        user.setStatus(1);
        user.setRoleId(2);
        // 取出Admin对象中的密码，将其加密，再存入到Admin对象中
//        String rawPassword = admin.getPassword();
//        String encodedPassword = passwordEncoder.encode(rawPassword);
//        admin.setPassword(encodedPassword);
        // 调用Mapper对象的insert()插入用户数据，并获取返回值
        log.debug("即将插入用户数据：{}", user);
        int rows = userMapper.insert(user);
        // 判断返回值是否不等于1
        if (rows != 1) {
            // 是：抛出ServiceException（ERR_INSERT）
            String message = "添加用户失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
    }

    @Override
    public void updateInfoById(Long id, UserUpdateDTO userUpdateDTO) {
        log.debug("开始处理【修改用户基本资料】的业务，id={}，新基本资料={}", userUpdateDTO);
        // 调用adminMapper根据参数id执行查询
        UserStandardVO queryResult = userMapper.getStandardById(id);
        // 判断查询结果是否为null
        if (queryResult == null) {
            // 抛出ServiceException，业务状态码：40400
            String message = "修改用户基本资料失败！尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 创建User对象，将作为修改时的参数
        User user = new User();
        BeanUtils.copyProperties(userUpdateDTO, user);
        user.setId(id);
        // 调用Mapper对象的update()修改用户基本资料，并获取返回值
        log.debug("即将修改用户基本资料：{}", user);
        int rows = userMapper.update(user);
        // 判断返回值是否不等于1
        if (rows != 1) {
            // 是：抛出ServiceException（ERR_INSERT）
            String message = "修改用户基本资料失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }

    @Override
    public void deleteById(Long id) {
        log.debug("开始处理【根据id删除用户】的业务：id={}", id);
        // 不允许对id=1的用户进行危险管理操作，返回NOT_FOUND错误，视为id=1的用户不存在
        if (id == 1) {
            // 抛出ServiceException，业务状态码：40400
            String message = "删除用户失败！尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 调用UserMapper根据参数id执行查询
        UserStandardVO queryResult = userMapper.getStandardById(id);
        // 判断查询结果是否为null
        if (queryResult == null) {
            // 抛出ServiceException，业务状态码：40400
            String message = "删除用户失败！尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 调用UserMapper根据参数id删除用户的数据，并获取返回值
        int rows = userMapper.deleteById(id);
        // 判断返回值是否不为1
        if (rows != 1) {
            // 抛出ServiceException，业务状态码：DELETE对应的常量
            String message = "删除用户失败！服务器忙，请稍后再次尝试！[错误代码：1]";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }

    }

    @Override
    public void setEnable(Long id) {
        log.debug("开始处理【启用用户账号】的业务：id={}", id);
        // 不允许对id=1的用户进行危险管理操作，返回NOT_FOUND错误，视为id=1的用户不存在
        if (id == 1) {
            // 抛出ServiceException，业务状态码：40400
            String message = "启用用户账号失败！尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 根据id查询用户数据
        UserStandardVO queryResult = userMapper.getStandardById(id);
        // 判断查询结果是否为null
        if (queryResult == null) {
            // 是：ServiceException：NOT_FOUND
            String message = "启用用户账号失败！尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 判断查询结果中的enable是否为1
        if (queryResult.getStatus() == 1) {
            // 是：ServiceException：CONFLICT
            String message = "启用用户账号失败！当前账号已经启用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
        User user = new User();
        user.setId(id);
        user.setStatus(1);
        // 执行更新，获取返回值
        int rows = userMapper.update(user);
        // 判断返回值是否不为1
        if (rows != 1) {
            // 是：ServiceException：UPDATE
            String message = "启用用户账号失败！服务器忙，请稍后再次尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }

    }

    @Override
    public void setDisable(Long id) {
        log.debug("开始处理【禁用用户账号】的业务：id={}", id);
        // 不允许对id=1的用户进行危险管理操作，返回NOT_FOUND错误，视为id=1的用户不存在
        if (id == 1) {
            // 抛出ServiceException，业务状态码：40400
            String message = "禁用用户账号失败！尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 根据id查询用户数据
        UserStandardVO queryResult = userMapper.getStandardById(id);
        // 判断查询结果是否为null
        if (queryResult == null) {
            // 是：ServiceException：NOT_FOUND
            String message = "禁用用户账号失败！尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 判断查询结果中的enable是否为1
        if (queryResult.getStatus() == 0) {
            // 是：ServiceException：CONFLICT
            String message = "禁用用户账号失败！当前账号已经禁用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        User user = new User();
        user.setId(id);
        user.setStatus(0);
        // 执行更新，获取返回值
        int rows = userMapper.update(user);
        // 判断返回值是否不为1
        if (rows != 1) {
            // 是：ServiceException：UPDATE
            String message = "禁用用户账号失败！服务器忙，请稍后再次尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }
}
